package cn.jrainbow.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Hibernate工具包
 * 
 * @author rainbow 
 */
public class HibernateUtil {
	/**
	 * JavaSE提供的类型头
	 */
	private static String javaType = "java";
	/**
	 * Hibernate取出来的List数据提前加载懒加载数据
	 * 解决Hibernate懒加载转json的问题
	 * @param list 源集合
	 * @param clazz 实体类
	 * @return
	 * @throws Exception 
	 */
	public static List listWithLazyData(List list,Class clazz) throws  Exception{
		List newList = new ArrayList();
		for(int i=0;i<list.size();i++){
			Object object =loadLazyData(list.get(i), clazz);
			newList.add(object);
		}
		
		return newList;
	}
	
	/**
	 * 单个对象提前加载懒加载数据
	 * 解决Hibernate懒加载转json的问题
	 * @param src 源对象
	 * @param clazz 实体类
	 * @return
	 * @throws Exception
	 */
	public static Object loadLazyData(Object src,Class clazz) throws Exception{
		Object object = src;
		Method[] originalMethods= clazz.getDeclaredMethods();
		for(Method originalMethod:originalMethods){
			if(originalMethod.getName().contains("get")){
				String returnType=originalMethod.getReturnType().getName();
				if(!returnType.startsWith(javaType)){
					//不是基本类型和集合，即是二级对象
					Object proxyObjct=originalMethod.invoke(object, null);
					if(proxyObjct!=null){
						Class proxyClass=proxyObjct.getClass();
						Method[] proxyMethods=proxyClass.getDeclaredMethods();
						
						Class tempClazz=Class.forName(returnType);
						Object tempObject=tempClazz.newInstance();
						
						for(Method proxyMethod:proxyMethods ){
							if(proxyMethod.getReturnType().getName().contains(javaType)){
								if(proxyMethod.getName().startsWith("get")){
									Object returnValue=proxyMethod.invoke(proxyObjct, null);
									String setMethod=proxyMethod.getName().replace("get", "set");
									Method tempMethod=tempClazz.getDeclaredMethod(setMethod, proxyMethod.getReturnType());
									tempMethod.invoke(tempObject, returnValue);
								}
							}
						}
						Method originalSetMethod=clazz.getDeclaredMethod(originalMethod.getName().replace("get", "set"), originalMethod.getReturnType());
						originalSetMethod.invoke(object, tempObject);
					}
				}
			}
		}
		
		return object;
	}
	
	/**
	 * 生成hql
	 *
	 * @param object 实体类对象
	 * @param alias 别名
	 * @return
	 * @throws Exception
	 */
	public static String createHQL(Object object,String alias) throws Exception {
		StringBuffer hql = new StringBuffer();
		Map<String, String> params = createParams(object);
		
		Set<Map.Entry<String, String>> set = params.entrySet();
		hql.append(" 1=1 ");
        for (Iterator<Map.Entry<String, String>> it = set.iterator(); it.hasNext();) {
            Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();
            hql.append(" and ").append(alias).append(".").append(entry.getKey());
            if(entry.getKey().contains(".")){
            	hql.append(" ='").append(entry.getValue().trim()).append("' ");
            }else{
            	hql.append(" like '%").append(entry.getValue().trim()).append("%' ");
            }
        }

		return hql.toString();
	}

	/**
	 * 获取查询的参数
	 * 
	 * @param object
	 * @return
	 * @throws Exception
	 */
	private static Map<String, String> createParams(Object object) throws Exception {
		Map<String, String> params = new HashMap<String, String>();
		
		setIntoParams(params,object, null);
		return params;
	}

	private static void setIntoParams(Map<String, String> params,Object object, String fatherName) throws IllegalAccessException,
			Exception {
		Field[] fields = object.getClass().getDeclaredFields();
		for (Field file : fields) {
			boolean accessFlag = file.isAccessible();
			file.setAccessible(true);
			String name = file.getName();
			Object value = file.get(object);
			
			if(file.getType().getName().equals("java.lang.Class")){
				break;
			}else if(file.getType().getName().contains(javaType)){
				if(fatherName != null && !fatherName.equals(" ")){
					name = fatherName+"."+name;
				}
				
				if(value != null){
					params.put(name, value+"");
				}
				
				
			}else{
				if(value != null){
					setIntoParams(params,file.get(object), name);
				}
				
			}
			file.setAccessible(accessFlag);
		}
	}
}
